home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / unix / uucp103d / part10 < prev    next >
Encoding:
Internet Message Format  |  1990-02-04  |  49.1 KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i054: uucp 1.03D - unix compatible uucp/mail/news system, Part10/16
  5. Message-ID: <11293@xanth.cs.odu.edu>
  6. Date: 4 Feb 90 02:38:27 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: overload!dillon (Matt Dillon)
  9. Lines: 1808
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12.  
  13. Submitted-by: overload!dillon (Matt Dillon)
  14. Posting-number: Volume 90, Issue 054
  15. Archive-name: unix/uucp-1.03d/part10
  16.  
  17. #!/bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 10 (of 16)."
  24. # Contents:  src/dmail/dmail.help src/sendmail/sendmail.c
  25. # Wrapped by tadguy@xanth on Sat Feb  3 20:51:17 1990
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'src/dmail/dmail.help' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'src/dmail/dmail.help'\"
  29. else
  30. echo shar: Extracting \"'src/dmail/dmail.help'\" \(23627 characters\)
  31. sed "s/^X//" >'src/dmail/dmail.help' <<'END_OF_FILE'
  32. X
  33. X'help TOPIC' for more information on a command.  Many commands take
  34. Xmessage numbers or message lists:
  35. X    [msg]    is an optionaly specified message number (usually the
  36. X        operation is on the current message if no number is
  37. X        specified)
  38. X    <list>    is an optionaly specified message list.  Message lists
  39. X        consists of number ranges of the form N -N N- or N-N, and
  40. X        keywords (help keywords)
  41. X
  42. X
  43. XOTHER HELP AVAILABLE (in addition to the commands):
  44. X    pager sendmail tilde header newmail keywords enviroment
  45. X
  46. XDMAIL written by Matthew Dillon, U.C. Berkeley -UCF
  47. X
  48. X(C)Copyright 1985-1989 by Matthew Dillon
  49. X
  50. X.pager
  51. Xset page [rows/command]
  52. X
  53. X    'page' is a SET variable which determines the type of paging list and
  54. Xdisplay commands will use.  If not defined, no filter is used.    If a numerical
  55. Xvalue (i.e. 24) is specified, the page length will be set to that value and
  56. Xa rather stupid, simple internal paging routine will be used.  If the
  57. Xvariable is set to an alpha-numeric string, output will be piped through
  58. Xthat filter.  For instance:
  59. X
  60. X    unset page        -no paging
  61. X    set page more        -use more filter
  62. X    set page page        -use 'page' filter
  63. X    set page > x        -redirect to a file (be careful)
  64. X    set page 24        -use internal paging, page length 24 rows.
  65. X
  66. X    For internal paging, use <return> to continue, or your INTR
  67. Xcharacter to break out.  Note that if you have paging set to a program,
  68. Xresponse time may be slower because dmail must execute that program.
  69. X
  70. X.sendmail
  71. Xset sendmail sendmail-path
  72. X
  73. X    Inform DMAIL as to where the sendmail program is.  The default
  74. X(variable unset) is /usr/lib/sendmail.  This variable is useful only for
  75. Xthose of us who like to hack-up our own sendmail.
  76. X
  77. X.tilde
  78. X~ ~user directory expansion
  79. X
  80. X    In all expressions except those within double quotes, the tilde
  81. X`~` will be expanded to either your home directory, or the directory of
  82. Xa specified user, depending.  Note that '*' and '?' are not expanded by
  83. XDMAIL, though they will be by any shell commands you execute.
  84. X
  85. X    It is probably a good idea to use ~ in any aliases, etc... in case
  86. Xyou change directories using the 'cd' command.
  87. X
  88. X    alias resource source ~/.dmailrc        -example using ~
  89. X
  90. X.header
  91. Xset header filepath
  92. X
  93. X    Set the location of your header file, which will appended to the
  94. Xscratch mail file before you are placed in the editor (usually vi).
  95. X
  96. X    set header ~/.header            -set header file to ~/.header
  97. X    unset header                -no header file
  98. X
  99. X.newmail
  100. XWhen new mail comes in:
  101. X
  102. X    Whenever newmail arrives, it will be automatically incorporated into
  103. Xa running DMAIL.  However, to see it, you must 'select all' (or select on
  104. Xanything that would include it).
  105. X
  106. X.keywords
  107. X.range
  108. X.message
  109. XKEYWORDS, MESSAGE LISTS
  110. X
  111. X    Many commands in DMAIL require a range of messages be given.  A Range
  112. Xconsists of message numbers (3 4 5), message ranges (1-45 -9 9-), and
  113. Xkeywords.  Keywords select certain messages from the entire SELECTED list:
  114. X
  115. X    all        -All messages
  116. X    tag        -All TAGGED messages
  117. X    mark        -All MARKED (read) messages
  118. X    deleted     -All DELETED messages
  119. X    written     -All WRITTEN messages
  120. X    untag        -All messages NOT TAGGED
  121. X    unmark        -All messages NOT MARKED (i.e. read)
  122. X    undeleted    -All messages NOT DELETED
  123. X    unwritten    -All messages NOT WRITTEN
  124. X
  125. X    Only the first three letters need be specified.  For instance, the
  126. X'all' keyword selects all the messages currently selected.  You could select
  127. Xon some subject, say, and then 'delete all'.
  128. X
  129. X    The message number 0 refers to the last message. the 'undeleted'
  130. Xkeyword exists only for completeness; you will probably never use it.
  131. X
  132. X.ver
  133. X.version
  134. XVER
  135. X
  136. X    returns the version number.
  137. X
  138. X.if
  139. X.else
  140. X.endif
  141. XIF [!]variable
  142. XELSE
  143. XENDIF
  144. X
  145. X    Conditionals.  Example:
  146. X
  147. X    if verbose
  148. X        .... do stuff if the variable exists
  149. X    else
  150. X        ... do stuff if the variable does not exist
  151. X    endif
  152. X    if !page; echo no page variable; endif
  153. X
  154. X.nobreak
  155. X.breakok
  156. XNOBREAK
  157. XBREAKOK
  158. X
  159. X    Disable or Enable your INTR key.  This command is stackable, thus
  160. Xthere is no problem with recursive aliases which use it.  Be careful that
  161. Xyou match any NOBREAK to a BREAKOK, or you may accidently put yourself into
  162. XNOBREAK mode (and a single BREAKOK may not fix it because it's stackable).
  163. X
  164. X    A good example would be a command which needs the page variable set
  165. Xfor the duration... say an alias to TYPE to a file:
  166. X
  167. Xalias file "%_a nobreak; set _b $page; set page cat > $_a; type; set page $_b; unset _b; breakok"
  168. X
  169. X    You can see that if the user were to hit his INTR character at the
  170. Xwrong time, the page variable would be incorrectly set.  The nobreak/breakok
  171. Xcommands fix this problem.  For simplicity, most people don't bother with
  172. Xbreak/nobreak, as it clutter's aliases up.
  173. X
  174. X.delete
  175. XDELETE <message list>
  176. X
  177. X    Mark the specified messages for deletion.  They will no longer show up
  178. Xon LISTings, (gaps will appear in message numbering).  However, you can
  179. Xstill TYPE them, if you remember the message number, and you can always
  180. XUNDELETE them.    Remember that the particular message # you've deleted
  181. Xmay be different if you change the SELECT parameters.  For example,
  182. Xmessage #3 selecting 'To' & 'foo' may actually be message #45 when you
  183. Xare selecting ALL (see SELECT).  Upon a QUIT, messages marked for
  184. Xdeletion are actually deleted from the mail file.
  185. X
  186. X.undelete
  187. XUNDELETE   <message list>
  188. X
  189. X    UNDELETES messages.  Without arguments, UNDELETE will
  190. Xrestore the last message you deleted.  Specifying 'all' (undelete all), will
  191. Xundelete any deleted messages in the currently selected message list.
  192. X
  193. X.header
  194. XHEADER [message]
  195. X
  196. X    Display the entire header of a message.  This does not cause the
  197. Xmessage to be marked 'read'.  TYPE, on the other hand, only displays
  198. Xheader information specified by SETLIST.
  199. X
  200. X.type
  201. XTYPE [message]
  202. X
  203. X    Type the text of a message.  Only header fields defined by SETLIST
  204. Xare displayed.    Otherwise, only the text is displayed.    This marks
  205. Xthe particular message as 'read', and also makes that message the
  206. Xcurrent message.
  207. X
  208. X.echo
  209. XECHO [string]
  210. X
  211. X    Echo the given string onto the screen.
  212. X
  213. X.go
  214. XGO #
  215. X    go to a message, don't type it out or anything.  Remember that you
  216. Xcan go to the last message by using the message # 0.  By placing a keyword
  217. X(help range), you can go to the first TAGGED message, etc...
  218. X
  219. X.reply
  220. X.Reply
  221. XREPLY
  222. X
  223. X    Reply to the current letter.  There are two forms of 'reply'.  The
  224. Xfirst does not include the senders original letter, the second does.
  225. XIn both cases, Dmail will place you in VI, with the To:, Cc:, and
  226. Xsubject lines filled out.  The second form is 'Reply', with an
  227. Xupper case 'R'.  This form includes the sender's message shifted to
  228. Xthe right with '>'s on the left hand side.  See FORWARD for another
  229. Xmethod of replying to mail.
  230. X
  231. X    In any case, you may get the sender's letter by reading the file '#'
  232. Xfrom VI.  That sequence would be ':r\\#'
  233. X
  234. X    See MAIL for more information on VI
  235. X
  236. X.forward
  237. XFORWARD [user user user....]
  238. X
  239. X    Forward the current message to a list of users.  The sender's
  240. Xentire message is placed in the text portion.  The To: field will
  241. Xcontain the user's named above, and the Subject: field will contain
  242. Xa 'Fo:' (you append your own subject)
  243. X
  244. X    See MAIL for more information on VI
  245. X
  246. X.mail
  247. XMAIL [user user user user...]
  248. X
  249. X    Mail to [users].  You are given a VI to work from, and may modify
  250. Xany of the header fields.  the From: field is inserted automatically
  251. Xby SENDMAIL, but you can overide it if you wish.
  252. X
  253. X    Quitting out of VI without writing the output file will cause an
  254. Xabort, and no mail will be sent.   Additionaly, you may use the 'vibreak'
  255. Xvariable to enable your INTR character (usually CTL-C) to break you out of
  256. XVI.
  257. X
  258. X    When modifying the users list in To and Cc fields, remember that
  259. Xthey should be all comma delimited, or none comma delimited.
  260. X
  261. X.select
  262. XSELECT ALL
  263. XSELECT Field  match match match match...
  264. XSELECT Field  !match
  265. XSELECT Field  match match match , Field match , .....
  266. X
  267. X    Select what you want to look at.  Select will take the field header
  268. Xyou supply and attempt to match arguments with that field in the mail
  269. Xfile.  You can then work on the selected material as if the rest of
  270. Xyour mail didn't exist.  For instance, 'select To dillon', will select
  271. Xall messages addressed to you.    Note that case is checked for the
  272. XFIELD-HEADER, but not for arguments, so the latter will also find
  273. Xanything addressed to Dillon or DILLON.  You only have to give a
  274. Xpartial match, so 'select To di' would work just as well.
  275. X
  276. X    Select then, allows you to quickly find what you want even though
  277. Xyou may have 12000 messages (though it may take a while with that many)
  278. XYou may also specify what you DON'T want to select on:
  279. X
  280. X select To !foo
  281. X
  282. Xwill select all letters not addressed to 'foo'.  You may select on any
  283. Xfield you wish.  At any time, you may say 'select ALL' to select the
  284. Xentire message list.  Use RESELECT to select on the current message
  285. Xlist.  SELECT always selects from the entire message-list
  286. X
  287. X select Cc hack , To hack
  288. X
  289. Xwill select any mail with Cc or To fields containing hack.  You may
  290. Xhave as many comma operators as you wish.  The comma must be a field
  291. Xof its own (spaces on either side... will be fixed in a later version)
  292. X
  293. X.reselect
  294. XRESELECT ALL
  295. XRESELECT Field    match match match match...
  296. XRESELECT Field    !match
  297. X
  298. X    SEE SELECT.  Reselect allows you to CONTINUE to narrow down a topic
  299. Xor whatever.  It will select on the current message list (which you have
  300. Xalready narrowed down with SELECT or RESELECT).
  301. X
  302. X.defer
  303. XDEFER
  304. X
  305. X    Deselects any marked messages .. messages marked as 'read'.  This is
  306. Xas if you did a RESELECT on all unread messages in the current select field.
  307. XThus, the messages will be renumbered.    To see these messages again, you must
  308. Xuse SELECT.
  309. X
  310. X.rlist <num>
  311. XRLIST <num>        -<num> > 0 (next N), < 0 (prev N).
  312. XRLIST            -Lists next 20 (or previous 20 if near the end)
  313. X
  314. X    Relative list.    See LIST for details of the list command.  This
  315. Xcommand will display the next <num> messages beginning at the current
  316. Xmessage.  If <num> is negative, it displays the previous 20 ending at
  317. Xthe current message.  If there are not enough messages remaining in the
  318. Xforward or reverse direction, it lists in the opposite direction to try
  319. Xto bring the total messages listed to <num>
  320. X
  321. X.list
  322. XLIST <message list>
  323. XLIST            -Lists all selected messages
  324. X
  325. X    Display header information on a message as specified by SETLIST,
  326. Xin a one line per message format.  The default lists ALL messages.
  327. X
  328. XLeftword flags:    r    -indicates message has been read.  Message will be
  329. X             moved to the destination file on QUIT
  330. X           >    -indicates message is the current message
  331. X           w    -indicates message has been written to a file.
  332. X             Message will be deleted from source file on QUIT
  333. X           T    -indicates message has been taged by the user
  334. X
  335. X.next
  336. XNEXT
  337. X
  338. X    Execute TYPE or HEADER for the next message, depending on which of
  339. XTYPE or HEADER was last executed by you
  340. X
  341. X._next
  342. X_NEXT
  343. X
  344. X    Go to next message, do not print it out.
  345. X
  346. X.back
  347. XBACK
  348. X
  349. X    Execute TYPE or HEADER for the previous message, depending on which
  350. Xof TYPE or HEADER was last executed by you
  351. X
  352. X._back
  353. X_BACK
  354. X
  355. X    Go to previous message, do not print it out.
  356. X
  357. X.db
  358. XDB
  359. X    Delete the current message, type (or header) the previous message.
  360. XThis command could not be implemented with "del;prev" due to a special case
  361. Xwhen one is on the last message.
  362. X
  363. X.dt
  364. XDT
  365. X    Delete current message, type (or header) next message.  This command
  366. Xwill warn you when you reach the end of the message list.
  367. X
  368. X    References: DELETE and NEXT
  369. X
  370. X.enviroment
  371. XENVIROMENT VARIABLE ACCESS
  372. X
  373. X    Access may be gained to enviroment variables by using $$ instead of
  374. X    a single $.  For example:  echo $$USER
  375. X
  376. X    'help dmail' for command line options,
  377. X    'help set'   for description of special variables
  378. X
  379. X.set
  380. XSET [variable [string]]
  381. X
  382. X    see 'enviroment' for enviroment variables
  383. X
  384. X    With no arguments, SET prints out all currently active variables.
  385. XNote that this variable list is a different list than the ALIAS list.  With
  386. Xone argument, the specified variable is displayed if it exists, or created
  387. Xif it doesn't.  With more than one argument, the specified variable is set
  388. Xto the specified string.  Variables may be references on the command line by
  389. X$variable .  The variable's contents will replace the reference.  Unlike
  390. Xaliases, however, variable substitutions may take place anywhere on the
  391. Xcommand line rather than substitute just the command name.  Note also that
  392. Xif you use a $ substitution for an argument of a command, the entire
  393. Xvariable's contents is ONE argument (i.e. if a = "b c d", and you say
  394. Xsomething like: 'unset $a', it would attempt to unset a single variable
  395. Xwhos name is "b c d".
  396. X
  397. X    There are several reserved SET variables, which define options in
  398. XDMAIL.    Changing these will modify the option:
  399. X
  400. X    page        set paging on or to a specific command (i.e. more)
  401. X    sendmail    set the path to the sendmail program
  402. X    vibreak     enable your INTR character even when in VI.
  403. X    verbose     reflects verbose option to sendmail
  404. X    comlinemail    set when dmail executed w/ command line mailing list
  405. X    header        header file to append to any messages you send.
  406. X    ask        ask what to do after vi'ing mail
  407. X    archive     file to archive any mail you send out in.
  408. X    _headchar    string used to precede included text, default ">"
  409. X    replyfields    fields to search to find the reply path
  410. X
  411. X    page
  412. X
  413. X     This variable determines what kind of paging is used for LIST,
  414. X     TYPE, and HEADER commands.  If the variable does not exist, paging
  415. X     is turned off.  If set to null (no string), an internal paging
  416. X     routine is used.  If set to a value, an internal paging routine is
  417. X     used using the value as the page length.  the 'page' variable can
  418. X     also be set to a command, such as 'more' or 'page', in which case,
  419. X     the output is piped through those commands:
  420. X
  421. X     set page        Turn paging on (internal page routine)
  422. X     set page 25        Internal page routine... 25 rows/screen
  423. X     set page more        Use 'more' command to pipe output through
  424. X     set page page        Use 'page' command to pipe output through
  425. X
  426. X     you could also conceviably say:  'set page cat > x', or
  427. X     'set page cat | lpr', but be very careful.
  428. X
  429. X    sendmail
  430. X
  431. X     This variable will redirect DMAIL as to where the mailer program
  432. X     is.  The mailer program must be compatible with /usr/lib/sendmail
  433. X     which is the default used if the 'sendmail' variable isn't set
  434. X     to anything:
  435. X
  436. X     set sendmail bin/mysendmail
  437. X
  438. X    vibreak
  439. X
  440. X     This variable, when set, allows the INTR character to abort a
  441. X     reply, mail, or forward command.  Otherwise, if this variable is
  442. X     not present, INTR will not abort the above commands.
  443. X
  444. X    verbose
  445. X
  446. X     This variable, when set, causes the -v flag to be sent to
  447. X     sendmail.  In addition, DMAIL will wait for sendmail to complete
  448. X     before returning your prompt.
  449. X
  450. X    comlinemail
  451. X
  452. X     This variable is set when dmail is invoked with a command line
  453. X     user list (e.g.  dmail charlie mary mark). Usually, one uses
  454. X     this variable in an IF construct.  A good example would be that
  455. X     you may usually CD to a mail directory, but you don't want to
  456. X     CD when dmail is run with a command line user-list:
  457. X
  458. X        if !comlinemail
  459. X            cd  ...
  460. X
  461. X     alternate definition: The comlinemail variable will NOT be set
  462. X     if dmail is in interactive mode.
  463. X
  464. X    header
  465. X
  466. X     The file specified by this variable will be appended onto the temp
  467. X     vi files in reply and mail.  The file is appended before you go into
  468. X     vi, so when you do, what you see is still what you get.
  469. X
  470. X    ask
  471. X
  472. X     If set, dmail will ask you what to to (quit, send, re-edit) after you
  473. X     leave the editor when sending mail.  If not set, the mail is sent as
  474. X     soon as you leave the editor (unless you didn't write anything).
  475. X
  476. X    archive
  477. X
  478. X     If set (to a file name), any mail you send out (mail/reply/etc...)
  479. X     will be archived to this file.  Usually, you provide a fully
  480. X     specified path so cd's won't effect the file location.
  481. X
  482. X    _headchar
  483. X
  484. X     This string is prepend to any included text when you do an upper-case
  485. X     reply (R) command.
  486. X
  487. X    replyfields
  488. X
  489. X     This string holds a list of fields which are searched for to
  490. X     determine which one to use in the To: field of your reply.  If
  491. X     this variable does not exist or none of the specified fields could
  492. X     be found, the 'From ' (not From:) mail header will be used.  The
  493. X     search ends at the first field found.    Example:
  494. X
  495. X     set replyfields "Reply-To: From:"
  496. X
  497. X.replyfields
  498. XSET replyfields "field1 field2 ..."
  499. X
  500. X     This string holds a list of fields which are searched for to
  501. X     determine which one to use in the To: field of your reply.  If
  502. X     this variable does not exist or none of the specified fields could
  503. X     be found, the 'From ' (not From:) mail header will be used.  The
  504. X     search ends at the first field found.    Example:
  505. X
  506. X     set replyfields "Reply-To: From:"
  507. X
  508. X.>
  509. XSET _HEADCHAR "string"
  510. X
  511. X    see SET.  The _headchar variable determines the string prepending all
  512. X    included text when you do an upper-case reply (R) command.
  513. X
  514. X.archive
  515. XSET ARCHIVE file
  516. X
  517. X    if the archive variable is set to a file path, any mail you send out
  518. X    will automatically be appended to that file.  Dmail pre-pends a
  519. X    "From ", so it is compatible with /bin/mail and so that you can
  520. X    dmail -f your archive file.  Additionaly, a "Date: " field is
  521. X    pre-pended so you know when you sent the message.  example:
  522. X
  523. X    set archive ~/Dmail/arch
  524. X
  525. X    since your .dmailrc is sourced even when you "dmail user .." from
  526. X    your csh, putting the above line in your .dmailrc will turn on
  527. X    archiving whenever you use dmail to send mail, command line or
  528. X    dmail prompt.
  529. X
  530. X    if unset or set to nothing, no archive is made.
  531. X
  532. X.ask
  533. XSET ASK
  534. X
  535. X    if the 'ask' variable is set (set ask), dmail will ask you what to do
  536. X    when you are finished editing mail rather than send it immediately.
  537. X    (see 'help set')
  538. X
  539. X.alias
  540. XALIAS [variable [string]]
  541. X
  542. X    Create an alias for a command.    With no arguments, ALIAS will display
  543. Xall active aliases.  With one argument, a particular alias is displayed (if
  544. Xit exists), or defined (if it did not previously exist).  With more than one
  545. Xargument, the particular alias is set to the string list specified.
  546. X
  547. Xalias
  548. Xalias hack "select From hacker , To hacker , Cc hacker"
  549. Xalias bye quit
  550. Xalias stuff "setlist 60 To ; list"
  551. X
  552. X    Usually, any arguments following the alias are appended to the
  553. Xexpansion.  However, you can place such arguments inside the alias somewhere
  554. Xby using the following construction:
  555. X
  556. Xalias myecho "%var echo $var ; list"
  557. X
  558. Xmyecho hello there  ---> echo hello there ; list
  559. X
  560. X    to unalias an alias, use the UNALIAS command.
  561. X
  562. X.unset
  563. X.unalias
  564. XUNSET var var var...
  565. XUNALIAS var var var...
  566. X
  567. X    Eradicate variables or aliases from memory.
  568. X
  569. X.setlist
  570. XSETLIST [-s] [columns] Field [columns] Field ...
  571. X
  572. X    -s prevents display of the list.
  573. XSet the list format used for LIST and TYPE.  The optional [columns]
  574. Xindicates how many columns to allocate for the Field specified.  The
  575. XField can be a partial match. However, case is observed:
  576. X
  577. Xsetlist 18 Fro    38 Sub    10 To  0 Dat
  578. X
  579. X18 columns for the From: field, etc... when TYPEing messages, the
  580. X[columns] is ignored, and each field is printed in its entirety.
  581. XNote that 0 columns have been allocated for the Date: field.
  582. XTherefore, the Date: field will not show up on the LIST command,
  583. Xbut will show up in the TYPE command.
  584. X
  585. X.cd
  586. XCD PATH
  587. X
  588. X    cd, as in csh.    Changes your base directory.  You can use
  589. X the shell escape '! pwd' to get your current working directory.
  590. X
  591. X.source
  592. XSOURCE file
  593. X
  594. X    Source a file.    The file is read in an executed in sequence.
  595. X
  596. X.preserve
  597. XPRE    <message list>
  598. X
  599. X    PRESERVE messages.  A message is MARKED if it has been read (has an 'r'
  600. Xflag from the LIST command).  Marked messages are moved from your readfile
  601. Xinto your outfile upon a QUIT.    If you are reading and writing to the same
  602. Xfile (i.e. from your mbox to your mbox), the 'r' flag has no effect.
  603. X
  604. X    However, if you are reading from your spool file, and want to keep
  605. Xread messages in your spool (that is, not move them to your mbox), you want
  606. Xto PRESERVE them.  This command simply unmarks them, so they appear not to
  607. Xhave been read.
  608. X
  609. X.mark
  610. XMARK <message list>
  611. X
  612. X    Mark messages specified as being already 'read'.  Remember that if
  613. Xyou executed DMAIL without a -f option, any message 'read' at the time
  614. Xyou quit will be moved to MBOX (or file specified by -o)
  615. X
  616. X.tag
  617. X.untag
  618. XTAG <list>
  619. XUNTAG <list>
  620. X
  621. X    The TAG command allow you to flag any message.    You can tag a set of
  622. Xmessages, then reference them all at once.  For instance, if you tag
  623. Xinteresting messages as you glance at them, you may then write them all
  624. Xto a file by 'write filename tag',  or list them with 'list tag'.
  625. XAlternately, you could delete all your taged messages with a single delete
  626. Xcommand 'delete tag'.  The 'tag' operand works in the same way as the 'all'
  627. Xoperand, except it works only on taged messages.
  628. X
  629. X    UNTAG will untag a particular message in your message list.  For
  630. Xinstance, to untag any taged messages in the entire message list, you would:
  631. X
  632. X select all
  633. X untag all    OR     untag tag
  634. X
  635. X    Note that 'untag all' and 'untag tag' have the same effect.
  636. X
  637. X.write
  638. XWRITE file <message list>
  639. X
  640. X    Write the given messages or the current message to a file.  The file
  641. Xfile is appended to.  Remember that you may specify 'all' to write
  642. Xall messages in the current select field to the file.  Messages will be
  643. Xmarked as having been writen, and will be deleted from the mail file
  644. Xwhen you 'quit'.  However, you may cause them to be kept in the mail
  645. Xfile by UNdeleting the messages (i.e.  undelete all)
  646. X
  647. X    You can also TAG the messages you want to write, and say
  648. X'write file tag' to write to the file all taged messages.
  649. X
  650. X.!
  651. X! [shell command]
  652. X
  653. X    Give yourself a shell or execute a shell command.  The shell forked
  654. Xis that specified by your SHELL enviroment variable, or /bin/sh if there is
  655. Xno SHELL enviroment variable.
  656. X
  657. X.x
  658. X.exit
  659. XX (EXIT)
  660. X
  661. X    EXIT out of DMAIL without changing any files.  Usually, one exits
  662. Xwith QUIT, which would cause deleted messages to disappear, and TYPEd
  663. Xmessages to go to MBOX (if you did not use the -f option with DMAIL).
  664. X
  665. X    If your outfile is the same as your infile, reading a message does
  666. Xnot effect anything.
  667. X
  668. X.quit
  669. XQUIT
  670. X
  671. X    Quit out of DMAIL. Delete any messages that were marked for deletion
  672. Xand if you executed DMAIL on /usr/spool/mail/ (default), any mail
  673. Xmarked 'read' will be placed in MBOX in your home directory
  674. X
  675. X.xswitch
  676. X.qswitch
  677. XXSWITCH fromfile [tofile]
  678. XQSWITCH fromfile [tofile]
  679. X
  680. X    Switch to a different set of files.  XSWITCH doesn't modify your
  681. Xold from and to files before switching, QSWITCH works as if you had QUIT
  682. Xstuff before switching to another set of files.
  683. X
  684. X    If no [tofile] is specified, the new tofile will be the same as the
  685. Xfromfile you specify.
  686. X
  687. X.help
  688. X.?
  689. XHELP [topic]
  690. X
  691. X    Give me help on a topic
  692. X
  693. X.dmail
  694. XCOMMAND LINE OPTIONS FOR DMAIL
  695. X
  696. X    dmail -O [-l rcfile] -f [file] -o [file] -F field -F field -F field ...
  697. X
  698. X    Default conditions:
  699. X        Home directory gotten from password entry
  700. X        User gotten from password entry
  701. X        Visual editor set to /usr/ucb/vi
  702. X
  703. X        VI BREAKOUT enabled
  704. X        READ file is /usr/spool/mail/$USER
  705. X        WRITE file is $HOME/mbox
  706. X        From:,    To:, and Subject: fields will be loaded into memory.
  707. X
  708. X    HOME    enviroment variable becomes home directory
  709. X    USER    enviroment variable becomes user name
  710. X    VISUAL    enviroment variable becomes editor used
  711. X
  712. X    -O            Go into interactive mode, even if there is no
  713. X                mail to read.
  714. X
  715. X    -f [from file]        Specify spool file to get mail from. If no file
  716. X                Argument is given, $HOME/MBOX is used.
  717. X
  718. X    -o [to file]        Specify file to write to, If no Argument
  719. X                is given, $HOME/.MBOX is used.    Note that
  720. X                the default without -o is $HOME/MBOX
  721. X
  722. X    -f -o            With no file arguments causes both READ and
  723. X                WRITE files to be $HOME/.MBOX
  724. X
  725. X    -F field        Append this field to those which will be
  726. X                used on initial load.  If, During usage of the
  727. X                program you specify a field which is not in
  728. X                memory, DMAIL will be forced to re-load the
  729. X                entire spool file, which can take a long time
  730. X                if you have more than 64K in the file
  731. X
  732. X    -l rcfile        Use this as the rc file rather than .dmailrc
  733. X
  734. X    -L            Do not source the rc file on boot
  735. X
  736. X
  737. END_OF_FILE
  738. if test 23627 -ne `wc -c <'src/dmail/dmail.help'`; then
  739.     echo shar: \"'src/dmail/dmail.help'\" unpacked with wrong size!
  740. fi
  741. # end of 'src/dmail/dmail.help'
  742. fi
  743. if test -f 'src/sendmail/sendmail.c' -a "${1}" != "-c" ; then 
  744.   echo shar: Will not clobber existing file \"'src/sendmail/sendmail.c'\"
  745. else
  746. echo shar: Extracting \"'src/sendmail/sendmail.c'\" \(22055 characters\)
  747. sed "s/^X//" >'src/sendmail/sendmail.c' <<'END_OF_FILE'
  748. X
  749. X/*
  750. X *  SENDMAIL / RMAIL
  751. X *
  752. X *  (C) Copyright 1989-1990 by Matthew Dillon,  All Rights Reserved.
  753. X *
  754. X *  SENDMAIL <file -f from -t to -s subject -c cc -b bcc -r
  755. X *  RMAIL user
  756. X *
  757. X *  Example:    Sendmail <datafile -froot
  758. X *
  759. X *  From: line is automatically added but can be overriden by a From:
  760. X *  header in the file.  stdin is made up of a list of headers, a blank
  761. X *  line, and then data until EOF.
  762. X *
  763. X *  the -r option tells sendmail that this is incomming mail.
  764. X *  If av[0] begins with an 'r' for RMail instead of an 's' for
  765. X *  Sendmail, then the rmail argument format is used (rmail user),
  766. X *  as well as forcing -r.
  767. X */
  768. X
  769. X#include <exec/types.h>
  770. X#include <exec/lists.h>
  771. X#include <proto/all.h>
  772. X#include <stdio.h>
  773. X#include <stdlib.h>
  774. X#include <string.h>
  775. X#include <log.h>
  776. X#include <config.h>
  777. X#include <time.h>
  778. X#include <pwd.h>
  779. X#include <string.h>
  780. X#include "/version.h"
  781. X
  782. X#define RCVR_UUCP    1
  783. X#define RCVR_SENDMAIL    2
  784. X
  785. XIDENT(".03");
  786. X
  787. Xtypedef struct List    LIST;
  788. Xtypedef struct Node    NODE;
  789. X
  790. Xchar    *UserName;
  791. Xchar    *NodeName;
  792. Xchar    *DomainName;
  793. Xchar    *TimeZoneName;    /*  All caps, ex: PST             */
  794. Xchar    *DefaultNode;    /*  for addr formats we don't understand */
  795. XLIST    RecvList;    /*  Received:        */
  796. XLIST    FromList;    /*  last one rules  */
  797. XLIST    ToList;     /*  To:         */
  798. XLIST    CcList;     /*  Cc:         */
  799. XLIST    BccList;    /*  Bcc:        */
  800. XLIST    XccList;    /*  list of actual mail to be sent  */
  801. XLIST    SubjList;    /*  Subject:        */
  802. XLIST    HdrList;    /*  other headers not specifically parsed */
  803. Xchar    ScrBuf[1024];
  804. Xchar    ScrBuf2[1024];
  805. Xchar    TempFileBuf[256];
  806. Xint    Seq;        /*  UUCP sequence no    */
  807. Xchar    ROpt;        /*  Receive-Mail flag    */
  808. Xstatic char OrigFromLine[512];
  809. Xstatic char FromLine[512];  /*    'From ' line, if ROpt   */
  810. X
  811. Xchar    *TmpFileName();
  812. Xchar    *atime();
  813. Xvoid    PostPend();
  814. Xvoid    MakeToFixNode();
  815. Xvoid    MakeToAddrNode();
  816. Xvoid    ToFixup();
  817. Xvoid    FromFixup();
  818. Xvoid    DumpHeaderInfo();
  819. Xvoid    DumpHeader();
  820. Xvoid    DumpCombineHeader();
  821. Xvoid    IntegrateHeader();
  822. Xvoid    Usage();
  823. XFILE    *SendMailTo();
  824. XFILE    *OneMailTo();
  825. XFILE    *OneMailToUUCP();
  826. XFILE    *OneMailToUser();
  827. XFILE    *OneMailToFile();
  828. XFILE    *OneMailToPipe();
  829. XNODE    *FindHeader();
  830. XNODE    *MakeNode();
  831. X
  832. XCXBRK()
  833. X{
  834. X    return(0);
  835. X}
  836. X
  837. Xvoid
  838. XUsage()
  839. X{
  840. X    printf(
  841. X    "Sendmail -f user [-t address -c address -b address -s subject -r]\n"
  842. X    "RMail user\n"
  843. X    );
  844. X}
  845. X
  846. Xvoid
  847. Xmain(ac, av)
  848. Xchar *av[];
  849. X{
  850. X    short isRMail = 0;
  851. X    short isSendMail = 1;
  852. X    FILE *fi;
  853. X
  854. X    NewList(&RecvList);
  855. X    NewList(&FromList);
  856. X    NewList(&ToList);
  857. X    NewList(&CcList);
  858. X    NewList(&BccList);
  859. X    NewList(&XccList);
  860. X    NewList(&SubjList);
  861. X    NewList(&HdrList);
  862. X
  863. X    UserName = FindConfig("UserName");
  864. X    if (UserName == NULL) {
  865. X    puts("Sendmail: UserName not in UULIB:Config!");
  866. X    exit(1);
  867. X    }
  868. X    NodeName = FindConfig("NodeName");
  869. X    if (NodeName == NULL) {
  870. X    puts("Sendmail: NodeName not in UULIB:Config!");
  871. X    exit(1);
  872. X    }
  873. X    DomainName = FindConfig("DomainName");
  874. X    if (DomainName == NULL) {
  875. X    puts("Sendmail: DomainName not in UULIB:Config! using .UUCP");
  876. X    DomainName = ".UUCP";
  877. X    }
  878. X    DefaultNode = FindConfig("DefaultNode");
  879. X    TimeZoneName = FindConfig("TimeZone");
  880. X
  881. X    LoadAliases();
  882. X
  883. X    {
  884. X    char *ptr = av[0] + strlen(av[0]);
  885. X
  886. X    /*
  887. X     *  Skip path
  888. X     */
  889. X
  890. X    while (ptr >= av[0] && *ptr != ':' && *ptr != '/')
  891. X        --ptr;
  892. X    ++ptr;
  893. X
  894. X    if (*ptr == 'r' || *ptr == 'R') {
  895. X        isRMail = 1;
  896. X        isSendMail = 0;
  897. X    }
  898. X    }
  899. X
  900. X    if (isRMail) {
  901. X    char *addr = (ac == 2) ? av[1] : "Mailer-Daemon";
  902. X
  903. X    MakeNode(&BccList, addr);
  904. X    UserName = "postmaster";    /*  XXX  */
  905. X    ROpt = 1;            /*    no header processing */
  906. X    }
  907. X    if (isSendMail) {
  908. X    short i;
  909. X    char *arg;
  910. X    for (i = 1; i < ac; ++i) {
  911. X        arg = av[i];
  912. X        if (*arg != '-')
  913. X        Usage();
  914. X        switch(arg[1]) {
  915. X        case 'f':
  916. X        UserName = av[i+1];
  917. X        sprintf(ScrBuf, "%s@%s%s", av[i+1], NodeName, DomainName);
  918. X        MakeNode(&FromList, ScrBuf);
  919. X        ++i;
  920. X        break;
  921. X        case 't':
  922. X        MakeNode(&ToList, av[++i]);
  923. X        break;
  924. X        case 'c':
  925. X        MakeNode(&CcList, av[++i]);
  926. X        break;
  927. X        case 'b':
  928. X        MakeNode(&BccList, av[++i]);
  929. X        break;
  930. X        case 's':
  931. X        MakeNode(&SubjList, av[++i]);
  932. X        break;
  933. X        case 'r':
  934. X        ++ROpt;
  935. X        break;
  936. X        default:
  937. X        Usage();
  938. X        }
  939. X    }
  940. X    }
  941. X
  942. X    /*
  943. X     *    Read headers from input file.  Headers are not necessarily
  944. X     *    contained on a single line.  Maximum 4096 chars per header.
  945. X     */
  946. X
  947. X    if (ROpt) {
  948. X    fgets(ScrBuf, sizeof(ScrBuf), stdin);
  949. X    strcpy(OrigFromLine, ScrBuf);
  950. X    if (strncmp(ScrBuf, "From ", 5) != 0) {
  951. X        ulog(-1, "Receive mail, expected 'From ', got %s", ScrBuf);
  952. X    }
  953. X    strcpy(FromLine, "From ");
  954. X    PostPend(ScrBuf + 5, 1);
  955. X
  956. X    while (fgets(ScrBuf, sizeof(ScrBuf), stdin) && strncmp(ScrBuf, ">From ", 6) == 0) {
  957. X        strcpy(OrigFromLine, ScrBuf + 1);
  958. X        PostPend(ScrBuf + 6, 1);
  959. X    }
  960. X    strcpy(ScrBuf2, OrigFromLine + 5);
  961. X    PostPend(ScrBuf2, 0);
  962. X    } else {
  963. X    ScrBuf[0] = '\n';
  964. X    fgets(ScrBuf, sizeof(ScrBuf), stdin);
  965. X    }
  966. X    {
  967. X    static char Hdr[4096];
  968. X    short i = 0;        /*  index into Hdr  */
  969. X
  970. X    while (ScrBuf[0] != '\n') {
  971. X        char *ptr = ScrBuf;
  972. X        while (*ptr && *ptr != ' ' && *ptr != 9 && *ptr != ':')
  973. X        ++ptr;
  974. X        if (*ptr == ':') {  /*  found new header */
  975. X        if (i)          /*  Dump old header  */
  976. X            IntegrateHeader(Hdr, i);
  977. X        strcpy(Hdr, ScrBuf);
  978. X        i = strlen(Hdr);
  979. X        } else {        /*  append to existing header    */
  980. X        if (i == 0)
  981. X            puts("Expected a Header!");
  982. X        strcpy(Hdr + i, ScrBuf);
  983. X        i = i + strlen(Hdr + i);
  984. X        }
  985. X
  986. X        if (fgets(ScrBuf, sizeof(ScrBuf), stdin) == NULL)
  987. X        ScrBuf[0] = '\n';
  988. X    }
  989. X    if (i)
  990. X        IntegrateHeader(Hdr, i);
  991. X
  992. X    if (ScrBuf[0] != '\n') {
  993. X        puts("sendmail: no mail");
  994. X        exit(1);
  995. X    }
  996. X    }
  997. X
  998. X    /*
  999. X     *    Parse & fixup each To:, Cc:, and Bcc: field.
  1000. X     *
  1001. X     *    From:    we add the personal info arg from the password file
  1002. X     *    To:    we expand any aliases
  1003. X     */
  1004. X
  1005. X    if (ROpt == 0)
  1006. X    FromFixup(&FromList);
  1007. X    if (ROpt) {
  1008. X    ToFixup(&BccList);
  1009. X    } else {
  1010. X    ToFixup(&ToList);
  1011. X    ToFixup(&CcList);
  1012. X    ToFixup(&BccList);
  1013. X    }
  1014. X
  1015. X    /*
  1016. X     *    If no Subject: field add a dummy one
  1017. X     */
  1018. X
  1019. X    if (EmptyList(&SubjList))
  1020. X    MakeNode(&SubjList, "");
  1021. X
  1022. X    if (EmptyList(&FromList)) {
  1023. X    sprintf(ScrBuf, "%s@%s%s", UserName, NodeName, DomainName);
  1024. X    MakeNode(&FromList, ScrBuf);
  1025. X    }
  1026. X
  1027. X    fi = SendMailTo(&XccList, stdin);
  1028. X    if (fi && fi != stdin)
  1029. X    fclose(fi);
  1030. X    if (TempFileBuf[0])
  1031. X    remove(TempFileBuf);
  1032. X    UnLockFiles();
  1033. X}
  1034. X
  1035. X/*
  1036. X *  Strips string and creates named node which is appended to the
  1037. X *  given list.
  1038. X */
  1039. X
  1040. XNODE *
  1041. XMakeNode(list, str)
  1042. XLIST *list;
  1043. Xchar *str;
  1044. X{
  1045. X    NODE *node;
  1046. X    char *ptr;
  1047. X
  1048. X    while (*str == ' ' || *str == 9)
  1049. X    ++str;
  1050. X    for (ptr = str + strlen(str); ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr);
  1051. X    ++ptr;
  1052. X    *ptr = 0;
  1053. X    node = malloc(sizeof(NODE) + strlen(str) + 1);
  1054. X    node->ln_Name = (char *)(node + 1);
  1055. X    strcpy(node->ln_Name, str);
  1056. X    AddTail(list, node);
  1057. X    return(node);
  1058. X}
  1059. X
  1060. X/*
  1061. X *
  1062. X */
  1063. X
  1064. Xvoid
  1065. XMakeToFixNode(list, str, send)
  1066. XLIST *list;
  1067. Xchar *str;
  1068. Xchar *send;
  1069. X{
  1070. X    char *ptr;
  1071. X    short len;
  1072. X    short c;
  1073. X    void fixCallBack();
  1074. X
  1075. X    while (str < send && (*str == ' ' || *str == 9))
  1076. X    ++str;
  1077. X    for (ptr = send - 1; ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr);
  1078. X    ++ptr;
  1079. X
  1080. X    len = ptr - str;
  1081. X    if (len < 0)
  1082. X    return;
  1083. X
  1084. X    /*
  1085. X     *    str[0..len-1]
  1086. X     */
  1087. X
  1088. X    c = str[len];
  1089. X    str[len] = 0;
  1090. X
  1091. X    if (ROpt) {     /*  disallow remote asking for special options */
  1092. X    ulog(-1, "Received mail for %s", str);
  1093. X    if (str[0] == '>' || str[0] == '<' || str[0] == '|' || str[0] == ':' || str[0] == '/') {
  1094. X        ulog(-1, "SendMail, bad user %s", str);
  1095. X        return;
  1096. X    }
  1097. X    }
  1098. X
  1099. X    {
  1100. X    NODE *node = malloc(sizeof(NODE) + strlen(str) + 1);
  1101. X
  1102. X    node->ln_Name = (char *)(node + 1);
  1103. X    strcpy(node->ln_Name, str);
  1104. X    AddTail(list, node);
  1105. X    }
  1106. X
  1107. X    UserAliasList(str, fixCallBack);    /*  from lib/alias.c    */
  1108. X    str[len] = c;
  1109. X}
  1110. X
  1111. Xvoid
  1112. XfixCallBack(user)
  1113. Xchar *user;
  1114. X{
  1115. X    NODE    *node;
  1116. X
  1117. X    if (user[0] == '<') {
  1118. X    FILE *fi = fopen(user + 1, "r");
  1119. X    char *buf = malloc(256);
  1120. X
  1121. X    if (fi == NULL) {
  1122. X        ulog(-1, "Unable to open < file %s", user + 1);
  1123. X        return;
  1124. X    }
  1125. X    while (fgets(buf, 256, fi)) {
  1126. X        short i = 0;
  1127. X        short j;
  1128. X        while (buf[i] == ' ' || buf[i] == 9)
  1129. X        ++i;
  1130. X        if (buf[i] == 0 || buf[i] == '\n')
  1131. X        continue;
  1132. X        for (j = i; buf[j] && buf[j] != '\n' && buf[j] != ' ' && buf[j] != 9; ++j);
  1133. X        buf[j] = 0;
  1134. X        UserAliasList(buf, fixCallBack);
  1135. X    }
  1136. X    fclose(fi);
  1137. X    free(buf);
  1138. X    return;
  1139. X    }
  1140. X
  1141. X    ulog(-1, "Sendmail, Sending mail to %s", user);
  1142. X
  1143. X    if (user[0] == '\\')
  1144. X    ++user;
  1145. X
  1146. X    node = malloc(sizeof(NODE) + strlen(user) + 1);
  1147. X    node->ln_Name = (char *)(node + 1);
  1148. X    strcpy(node->ln_Name, user);
  1149. X    AddTail(&XccList, node);
  1150. X}
  1151. X
  1152. X
  1153. X/*
  1154. X *  Integrates a header
  1155. X */
  1156. X
  1157. Xvoid
  1158. XIntegrateHeader(hdr, len)
  1159. Xchar *hdr;
  1160. Xshort len;
  1161. X{
  1162. X    if (hdr[len-1] == '\n')     /*  strip trailing newline  */
  1163. X    hdr[len-1] = 0;
  1164. X
  1165. X    if (strncmp(hdr, "From:", 5) == 0) {
  1166. X    MakeNode(&FromList, hdr + 5);
  1167. X    return;
  1168. X    }
  1169. X    if (strncmp(hdr, "To:", 3) == 0) {
  1170. X    MakeNode(&ToList, hdr + 3);
  1171. X    return;
  1172. X    }
  1173. X    if (strncmp(hdr, "Cc:", 3) == 0) {
  1174. X    MakeNode(&CcList, hdr + 3);
  1175. X    return;
  1176. X    }
  1177. X    if (strncmp(hdr, "Bcc:", 4) == 0) {
  1178. X    MakeNode(&BccList, hdr + 4);
  1179. X    return;
  1180. X    }
  1181. X    if (strncmp(hdr, "Subject:", 8) == 0) {
  1182. X    MakeNode(&SubjList, hdr + 8);
  1183. X    return;
  1184. X    }
  1185. X    if (strncmp(hdr, "Received:", 9) == 0) {
  1186. X    MakeNode(&RecvList, hdr + 9);
  1187. X    return;
  1188. X    }
  1189. X    MakeNode(&HdrList, hdr);
  1190. X}
  1191. X
  1192. X/*
  1193. X *  Adds (personal info) to FromList based on passwd entry or, if
  1194. X *  that is not available, from the Config entry 'RealName'.
  1195. X */
  1196. X
  1197. Xvoid
  1198. XFromFixup(list)
  1199. XLIST *list;
  1200. X{
  1201. X    char *wholeName = GetConfig("RealName", "Who Knows");
  1202. X    NODE *node;
  1203. X    NODE *nn;
  1204. X    LIST tmpList;
  1205. X
  1206. X    NewList(&tmpList);
  1207. X
  1208. X    while (node = RemHead(list)) {
  1209. X    /*
  1210. X     *  FIXME.  Fix getpwnam() and use pw_gecos entry.
  1211. X     */
  1212. X    nn = malloc(sizeof(NODE) + strlen(node->ln_Name) + strlen(wholeName) + 16);
  1213. X    nn->ln_Name = (char *)(nn + 1);
  1214. X    sprintf(nn->ln_Name, "%s (%s)", node->ln_Name, wholeName);
  1215. X    free(node);
  1216. X    AddTail(&tmpList, nn);
  1217. X    }
  1218. X    while (node = RemHead(&tmpList))
  1219. X    AddTail(list, node);
  1220. X}
  1221. X
  1222. X/*
  1223. X *  Converts an unparsed list of names into a list of single address
  1224. X *  fields, removing any personal idents from the entries.  These will
  1225. X *  be recombined after processing when the data file is written out.
  1226. X *
  1227. X *  Also expands sendmail aliases (UULIB:Aliases) (HACK)
  1228. X */
  1229. X
  1230. Xvoid
  1231. XToFixup(list)
  1232. XLIST *list;
  1233. X{
  1234. X    NODE *node;
  1235. X    LIST tmpList;
  1236. X
  1237. X    NewList(&tmpList);
  1238. X
  1239. X    while (node = RemHead(list)) {
  1240. X    char *str = node->ln_Name;
  1241. X    char *ptr;
  1242. X
  1243. X    while (*str) {      /*  breakup fields by newline or comma */
  1244. X        for (ptr = str; *ptr && *ptr != '\n' && *ptr != ','; ++ptr);
  1245. X        MakeToAddrNode(&tmpList, str);
  1246. X        str = ptr;
  1247. X        while (*str == '\n' || *str == ',' || *str == ' ' || *str == 9)
  1248. X        ++str;
  1249. X    }
  1250. X    free(node);
  1251. X    }
  1252. X    while (node = RemHead(&tmpList))
  1253. X    AddTail(list, node);
  1254. X}
  1255. X
  1256. X/*
  1257. X *  Extracts a single name / address (comma or newline delimited)
  1258. X *  field and creates a new node.
  1259. X */
  1260. X
  1261. Xvoid
  1262. XMakeToAddrNode(list, str)
  1263. XLIST *list;
  1264. Xchar *str;
  1265. X{
  1266. X    char *p1, *p2;
  1267. X    short ns = 0;    /*  non-whitespace encountered */
  1268. X
  1269. X    for (p1 = str; *p1 && *p1 != ',' && *p1 != '\n'; ++p1) {
  1270. X    if (*p1 == '(') {   /*  addr (name) OR (name) addr */
  1271. X        if (ns) {       /*  addr (name) */
  1272. X        MakeToFixNode(list, str, p1);
  1273. X        } else {
  1274. X        while (*p1 && *p1 != ',' && *p1 != '\n' && *p1 != ')')
  1275. X            ++p1;
  1276. X        if (*p1 == ')') {
  1277. X            for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n'; ++p2);
  1278. X            MakeToFixNode(list, p1 + 1, p2);
  1279. X        }
  1280. X        }
  1281. X        return;
  1282. X    }
  1283. X
  1284. X    if (*p1 == '<') {   /*  <addr>  */
  1285. X        for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n' && *p2 != '>'; ++p2);
  1286. X        if (*p2 == '>')
  1287. X        MakeToFixNode(list, p1 + 1, p2);
  1288. X        return;
  1289. X    }
  1290. X    if (*p1 != ' ' && *p1 != 9)
  1291. X        ns = 1;
  1292. X    }
  1293. X    MakeToFixNode(list, str, p1);
  1294. X}
  1295. X
  1296. X
  1297. X/*
  1298. X *  Send mail to <recipeant>
  1299. X *
  1300. X *    -Local mail
  1301. X *    -Machine path (UUCP)
  1302. X */
  1303. X
  1304. XFILE *
  1305. XSendMailTo(list, fi)
  1306. XLIST *list;
  1307. XFILE *fi;
  1308. X{
  1309. X    NODE *node;
  1310. X
  1311. X    for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ)
  1312. X    fi = OneMailTo(node->ln_Name, fi);
  1313. X    return(fi);
  1314. X}
  1315. X
  1316. XFILE *
  1317. XOneMailTo(toaddr, rfi)
  1318. Xchar *toaddr;
  1319. XFILE *rfi;
  1320. X{
  1321. X    short i;
  1322. X    char c;
  1323. X    static char Buf[256];
  1324. X    static char typeBuf[16];
  1325. X    static char classBuf[16];
  1326. X    static char addrBuf[128];
  1327. X
  1328. X    if (toaddr[0] == '|')       /*  pipe through command    */
  1329. X    return(OneMailToPipe(toaddr + 1, rfi));
  1330. X    if (toaddr[0] == '>')       /*  copy to file            */
  1331. X    return(OneMailToFile(toaddr + 1, rfi));
  1332. X
  1333. X    for (i = 0; c = toaddr[i]; ++i) {
  1334. X    if (c == '!' || c == '%' || c == '@' || c == ':')
  1335. X        break;
  1336. X    }
  1337. X    if (c == 0)                 /*  local name  */
  1338. X    return(OneMailToUser(toaddr, rfi));
  1339. X
  1340. X    /*
  1341. X     *    Non-Local mail
  1342. X     */
  1343. X
  1344. X    i = ParseAddress(toaddr, Buf, strlen(toaddr));
  1345. X    if (DomainLookup(Buf, strlen(Buf), typeBuf, classBuf, addrBuf)) {
  1346. X    printf("type %s class %s addr %s\n", typeBuf, classBuf, addrBuf);
  1347. X    printf("buf %s\n", Buf);
  1348. X
  1349. X    /*
  1350. X     *  Note distinction between mail destination and mail forwarder.
  1351. X     *  mail destination removes the first machine from the rmail line
  1352. X     *  mail forwarder does NOT
  1353. X     */
  1354. X
  1355. X    if (strcmpi(classBuf, "UU") == 0) {
  1356. X        if (strcmpi(typeBuf, "MD") == 0)
  1357. X        return(OneMailToUUCP(addrBuf, Buf + i + 1, rfi));
  1358. X        else
  1359. X        return(OneMailToUUCP(addrBuf, Buf, rfi));
  1360. X    } else {
  1361. X        ulog(-1, "Unsupported domain class: %s", classBuf);
  1362. X        printf("Unsupported domain class: %s\n", classBuf);
  1363. X    }
  1364. X    return(rfi);
  1365. X    } else {
  1366. X    ulog(-1, "Could not find domain for %s, no mail sent", Buf);
  1367. X    printf("Unable to send mail to %s\n", Buf);
  1368. X    return(rfi);
  1369. X    }
  1370. X}
  1371. X
  1372. X
  1373. XFILE *
  1374. XOneMailToPipe(toaddr, rfi)
  1375. Xchar *toaddr;
  1376. XFILE *rfi;
  1377. X{
  1378. X    FILE *fi;
  1379. X    char *ptr;
  1380. X    static long pos;
  1381. X
  1382. X    if (TempFileBuf[0] == 0) {
  1383. X    strcpy(TempFileBuf, TmpFileName("T:pipe"));
  1384. X    fi = fopen(TempFileBuf, "w");
  1385. X    if (fi == NULL) {
  1386. X        ulog(-1, "Unable to open temp file %s for command: %s", TempFileBuf, toaddr);
  1387. X        return(rfi);
  1388. X    }
  1389. X    DumpHeaderInfo(fi, RCVR_SENDMAIL, 0, 1);
  1390. X    pos = ftell(fi);
  1391. X    while (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  1392. X        fputs(ScrBuf, fi);
  1393. X    fclose(fi);
  1394. X    }
  1395. X    strcpy(ScrBuf, toaddr);
  1396. X
  1397. X    ptr = toaddr;
  1398. X    if (strncmpi(toaddr, "run", 3) == 0) {
  1399. X    ptr += 3;
  1400. X    while (*ptr == ' ' || *ptr == 9)
  1401. X        ++ptr;
  1402. X    }
  1403. X    while (*ptr && *ptr != ' ' && *ptr != 9)
  1404. X    ++ptr;
  1405. X
  1406. X    if (*ptr == 0)
  1407. X    strcat(ScrBuf, " ");
  1408. X    sprintf(ScrBuf + (ptr - toaddr + 1), "<%s %s", TempFileBuf, ptr);
  1409. X    if (Execute(ScrBuf, NULL, NULL) == 0)
  1410. X    ulog(-1, "Couldn't execute %s", ScrBuf);
  1411. X
  1412. X    fi = fopen(TempFileBuf, "r");
  1413. X    if (fi) {
  1414. X    if (rfi != stdin)
  1415. X        fclose(rfi);
  1416. X    rfi = fi;
  1417. X    fseek(rfi, pos, 0);
  1418. X    } else {
  1419. X    ulog(-1, "Couldn't reopen temp '%s', mail failed!", TempFileBuf);
  1420. X    rfi = stdin;
  1421. X    }
  1422. X    return(rfi);
  1423. X}
  1424. X
  1425. XFILE *
  1426. XOneMailToUser(toaddr, rfi)
  1427. Xchar *toaddr;
  1428. XFILE *rfi;
  1429. X{
  1430. X    sprintf(ScrBuf, "UUMAIL:%s", toaddr);
  1431. X    return(OneMailToFile(ScrBuf, rfi));
  1432. X}
  1433. X
  1434. XFILE *
  1435. XOneMailToFile(tofile, rfi)
  1436. Xchar *tofile;
  1437. XFILE *rfi;
  1438. X{
  1439. X    FILE *fo;
  1440. X    static char DataFile[128];
  1441. X    long pos;
  1442. X
  1443. X    strcpy(DataFile, tofile);
  1444. X
  1445. X    LockFile(DataFile);
  1446. X    fo = fopen(DataFile, "a");
  1447. X    if (fo == NULL) {
  1448. X    strcpy(DataFile, "T:MailOverflow");
  1449. X    fo = fopen(DataFile, "a");
  1450. X    if (fo)
  1451. X        ulog(-1, "Could not append to %s, appending to %s", tofile, DataFile);
  1452. X    else
  1453. X        ulog(-1, "Can't append to anywhere! (%s)", tofile);
  1454. X    }
  1455. X    if (fo) {
  1456. X    DumpHeaderInfo(fo, RCVR_SENDMAIL, 0, 1);
  1457. X    pos = ftell(fo);
  1458. X    if (ROpt) {
  1459. X        if (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  1460. X        fputs(ScrBuf, fo);
  1461. X    }
  1462. X    while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) {
  1463. X        if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0)
  1464. X        strins(ScrBuf, " ");
  1465. X        fputs(ScrBuf, fo);
  1466. X    }
  1467. X    fclose(fo);
  1468. X    if (rfi != stdin)
  1469. X        fclose(rfi);
  1470. X    rfi = fopen(DataFile, "r");
  1471. X    fseek(rfi, pos, 0);
  1472. X    }
  1473. X    return(rfi);
  1474. X}
  1475. X
  1476. XFILE *
  1477. XOneMailToUUCP(toaddr, skipaddr, rfi)
  1478. Xchar *toaddr;
  1479. Xchar *skipaddr;
  1480. XFILE *rfi;
  1481. X{
  1482. X    static char ExecFile[128];
  1483. X    static char XExecFile[128];
  1484. X    static char CommandFile[128];
  1485. X    static char DataFile[128];
  1486. X    static char DestNode[256];
  1487. X    /*static char ToAddr[256];*/
  1488. X    FILE *fi;
  1489. X    int seq;
  1490. X    long pos;
  1491. X    short i;
  1492. X    short ai;
  1493. X
  1494. X    /*
  1495. X     *    If the destination node
  1496. X     */
  1497. X
  1498. X    strcpy(DestNode, toaddr);
  1499. X
  1500. X    ai = -1;
  1501. X    for (i = 0; DestNode[i]; ++i) {
  1502. X    /*
  1503. X     *  Remember index for additional paths
  1504. X     */
  1505. X
  1506. X    if (DestNode[i] == '!') {
  1507. X        DestNode[i] = 0;
  1508. X        ai = i + 1;
  1509. X        break;
  1510. X    }
  1511. X
  1512. X    /*
  1513. X     *  Cut off machine name at 7 chars and ignore any domain
  1514. X     *  info.
  1515. X     */
  1516. X
  1517. X    if (i == 7 || DestNode[i] == '.')
  1518. X        DestNode[i] = 0;
  1519. X    }
  1520. X
  1521. X    Seq = seq = GetSequence(4);
  1522. X
  1523. X#define FOFF    8
  1524. X
  1525. X    sprintf(ExecFile,   "UUSPOOL:D.%sX%04d", DestNode, seq++);
  1526. X    sprintf(XExecFile,  "UUSPOOL:X.%sX%04d", DestNode, seq++);
  1527. X    sprintf(CommandFile,"UUSPOOL:C.%sA%04d", DestNode, seq++);
  1528. X    sprintf(DataFile,   "UUSPOOL:D.%sB%04d", DestNode, seq);
  1529. X
  1530. X    LockFile(ExecFile);
  1531. X    LockFile(XExecFile);
  1532. X    LockFile(CommandFile);
  1533. X    LockFile(DataFile);
  1534. X
  1535. X    /*
  1536. X     *    Note, cannot run uuxqt from sendmail as uuxqt may call
  1537. X     *    sendmail!
  1538. X     */
  1539. X
  1540. X    if (strncmp(DestNode, NodeName, 7) == 0)
  1541. X    fi = fopen(XExecFile, "w");
  1542. X    else
  1543. X    fi = fopen(ExecFile, "w");
  1544. X
  1545. X    if (fi == NULL)
  1546. X    goto fail;
  1547. X
  1548. X    fprintf(fi, "U %s\n", UserName);
  1549. X    fprintf(fi, "F %s\n", DataFile + FOFF);
  1550. X    fprintf(fi, "I %s\n", DataFile + FOFF);
  1551. X    if (ai >= 0)
  1552. X    fprintf(fi, "C rmail %s!%s\n", DestNode + ai, skipaddr);
  1553. X    else
  1554. X    fprintf(fi, "C rmail %s\n", skipaddr);
  1555. X    fclose(fi);
  1556. X
  1557. X    if (strncmp(DestNode, NodeName, 7)) {
  1558. X    fi = fopen(CommandFile, "w");
  1559. X    if (fi == NULL)
  1560. X        goto fail;
  1561. X
  1562. X    fprintf(fi, "S %s %s %s - %s 0666\n", DataFile + FOFF, DataFile + FOFF, UserName, DataFile + FOFF);
  1563. X    fprintf(fi, "S %s %s %s - %s 0666\n", ExecFile + FOFF, XExecFile + FOFF, UserName, ExecFile + FOFF);
  1564. X    fclose(fi);
  1565. X    }
  1566. X
  1567. X    fi = fopen(DataFile, "w");
  1568. X    if (fi == NULL)
  1569. X    goto fail;
  1570. X
  1571. X    DumpHeaderInfo(fi, RCVR_UUCP, 1, 0);
  1572. X    pos = ftell(fi);
  1573. X
  1574. X    if (ROpt) {
  1575. X    if (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  1576. X        fputs(ScrBuf, fi);
  1577. X    }
  1578. X    while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) {
  1579. X    if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0)
  1580. X        strins(ScrBuf, " ");
  1581. X    fputs(ScrBuf, fi);
  1582. X    }
  1583. X    fclose(fi);
  1584. X    if (rfi != stdin)
  1585. X    fclose(rfi);
  1586. X    fi = fopen(DataFile, "r");
  1587. X    fseek(fi, pos, 0);
  1588. X    return(fi);
  1589. Xfail:
  1590. X    puts("Fail");
  1591. X    return(rfi);
  1592. X}
  1593. X
  1594. Xvoid
  1595. XDumpHeaderInfo(fi, rcvr, resend, local)
  1596. XFILE *fi;
  1597. X{
  1598. X    char *source;
  1599. X    time_t t;
  1600. X
  1601. X    time(&t);
  1602. X
  1603. X    /*
  1604. X     *    Write header info
  1605. X     */
  1606. X
  1607. X    if (rcvr == RCVR_UUCP)
  1608. X    source = "AmigaUUCP";
  1609. X    else
  1610. X    source = "Sendmail";
  1611. X
  1612. X    if (ROpt) {
  1613. X    if (resend)
  1614. X        fprintf(fi, "%s %s remote from %s\n", FromLine, atime(&t), NodeName);
  1615. X    else
  1616. X        fprintf(fi, "%s %s\n", FromLine, atime(&t));
  1617. X    } else {
  1618. X    if (local)
  1619. X        fprintf(fi, "From %s %s\n", UserName, atime(&t));
  1620. X    else
  1621. X        fprintf(fi, "From %s %s remote from %s\n", UserName, atime(&t), NodeName);
  1622. X    }
  1623. X    fprintf(fi, "Received: by %s%s (0.44/0.44)\n\tid AA%05d; %s\n",
  1624. X    NodeName, DomainName, Seq, atime(&t)
  1625. X    );
  1626. X    DumpHeader(fi, "Received:", &RecvList);
  1627. X    if (ROpt == 0) {
  1628. X    time_t t2 = t + 3600 * GetHourOffset(TimeZoneName);
  1629. X    struct tm *ut;
  1630. X
  1631. X    if (FindHeader("Date:") == NULL)
  1632. X        fprintf(fi, "Date: %s\n", atime(&t));
  1633. X    ut = localtime(&t2);
  1634. X    fprintf(fi, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s%s>\n",
  1635. X        ut->tm_year % 100, ut->tm_mon + 1, ut->tm_mday, ut->tm_hour, ut->tm_min,
  1636. X        Seq, NodeName, DomainName
  1637. X    );
  1638. X    }
  1639. X
  1640. X    /*
  1641. X     *    From:, To:, Cc:, Subject: (Bcc: never written to header),
  1642. X     *    and any other header fields
  1643. X     */
  1644. X
  1645. X    DumpHeader(fi, NULL, &HdrList);
  1646. X    DumpHeader(fi, "From:", &FromList);
  1647. X    DumpCombineHeader(fi, "To:", &ToList);
  1648. X    if (!EmptyList(&CcList))
  1649. X    DumpCombineHeader(fi, "Cc:", &CcList);
  1650. X    DumpHeader(fi, "Subject:", &SubjList);
  1651. X
  1652. X    fprintf(fi, "\n");
  1653. X}
  1654. X
  1655. Xvoid
  1656. XDumpHeader(fi, field, list)
  1657. XFILE *fi;
  1658. Xchar *field;
  1659. XLIST *list;
  1660. X{
  1661. X    NODE *node;
  1662. X
  1663. X    for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) {
  1664. X    if (field)
  1665. X        fprintf(fi, "%s %s\n", field, node->ln_Name);
  1666. X    else
  1667. X        fprintf(fi, "%s\n", node->ln_Name);
  1668. X    }
  1669. X}
  1670. X
  1671. XNODE *
  1672. XFindHeader(field)
  1673. Xchar *field;
  1674. X{
  1675. X    NODE *node;
  1676. X    short len = strlen(field);
  1677. X
  1678. X    for (node = HdrList.lh_Head; node != (NODE *)&HdrList.lh_Tail; node = node->ln_Succ) {
  1679. X    if (strncmp(node->ln_Name, field, len) == 0)
  1680. X        return(node);
  1681. X    }
  1682. X    return(NULL);
  1683. X}
  1684. X
  1685. Xvoid
  1686. XDumpCombineHeader(fi, field, list)
  1687. XFILE *fi;
  1688. Xchar *field;
  1689. XLIST *list;
  1690. X{
  1691. X    NODE *node;
  1692. X    short ci = 0;
  1693. X
  1694. X    fprintf(fi, "%s ", field);
  1695. X    for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) {
  1696. X    if (ci && ci + strlen(node->ln_Name) > 70) {
  1697. X        fprintf(fi, ",\n\t");
  1698. X        ci = 0;
  1699. X    }
  1700. X    if (ci)
  1701. X        fprintf(fi, ", ");
  1702. X    fprintf(fi, "%s", node->ln_Name);
  1703. X    ci += strlen(node->ln_Name) + 2;
  1704. X    }
  1705. X    fprintf(fi, "\n");
  1706. X}
  1707. X
  1708. Xchar *
  1709. Xatime(pt)
  1710. Xtime_t *pt;
  1711. X{
  1712. X    static char buf[40];
  1713. X    static char *mo[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1714. X                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1715. X            };
  1716. X    static char *dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  1717. X    struct tm *ut = localtime(pt);
  1718. X
  1719. X    sprintf(buf, "%s, %d %s %02d %02d:%02d:%02d %s",
  1720. X    dow[ut->tm_wday], ut->tm_mday, mo[ut->tm_mon],
  1721. X    ut->tm_year % 100, ut->tm_hour, ut->tm_min, ut->tm_sec,
  1722. X    TimeZoneName
  1723. X    );
  1724. X    return(buf);
  1725. X}
  1726. X
  1727. XGetHourOffset(tz)
  1728. Xchar *tz;
  1729. X{
  1730. X    short i;
  1731. X
  1732. X    static struct {
  1733. X    char *Name;
  1734. X    short Hours;
  1735. X    } TZAry[] = {
  1736. X    "GMT",  0,
  1737. X    "UT",   0,
  1738. X    "PST",  8,
  1739. X    "MST",  7,
  1740. X    "CST",  6,
  1741. X    "EST",  5,
  1742. X    "AST",  4,
  1743. X    "PDT",  7,
  1744. X    "MDT",  6,
  1745. X    "CDT",  5,
  1746. X    "EDT",  4,
  1747. X    "ADT",  3,
  1748. X    NULL, 0
  1749. X    };
  1750. X    for (i = 0; TZAry[i].Name; ++i) {
  1751. X    if (strncmp(tz, TZAry[i].Name, 3) == 0)
  1752. X        return((int)TZAry[i].Hours);
  1753. X    }
  1754. X    ulog(-1, "Unknown Timezone: %s", tz);
  1755. X    printf("Unknown Timezone: %s", tz);
  1756. X    return(6);
  1757. X}
  1758. X
  1759. Xvoid
  1760. XPostPend(str, frend)
  1761. Xchar *str;
  1762. X{
  1763. X    char *ptr;
  1764. X    if (frend) {
  1765. X    ptr = str + strlen(str);
  1766. X    while (ptr > str && *ptr != ' ' && *ptr != 9) {
  1767. X        if (*ptr == '\n')
  1768. X        *ptr = 0;
  1769. X        --ptr;
  1770. X    }
  1771. X    str = ptr + 1;
  1772. X    }
  1773. X    for (ptr = str; *ptr && *ptr != ' ' && *ptr != 9 && *ptr != '\n'; ++ptr);
  1774. X    if (frend)
  1775. X    strcpy(ptr, "!");
  1776. X    else
  1777. X    strcpy(ptr, "");
  1778. X    for (ptr = FromLine + 5; *ptr && *ptr != ' ' && *ptr != 9; ++ptr);
  1779. X    strins(ptr, str);
  1780. X}
  1781. X
  1782. XEmptyList(list)
  1783. XLIST *list;
  1784. X{
  1785. X    if (list->lh_Head == (NODE *)&list->lh_Tail)
  1786. X    return(1);
  1787. X    return(0);
  1788. X}
  1789. X
  1790. END_OF_FILE
  1791. if test 22055 -ne `wc -c <'src/sendmail/sendmail.c'`; then
  1792.     echo shar: \"'src/sendmail/sendmail.c'\" unpacked with wrong size!
  1793. fi
  1794. # end of 'src/sendmail/sendmail.c'
  1795. fi
  1796. echo shar: End of archive 10 \(of 16\).
  1797. cp /dev/null ark10isdone
  1798. MISSING=""
  1799. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do
  1800.     if test ! -f ark${I}isdone ; then
  1801.     MISSING="${MISSING} ${I}"
  1802.     fi
  1803. done
  1804. if test "${MISSING}" = "" ; then
  1805.     echo You have unpacked all 16 archives.
  1806.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1807. else
  1808.     echo You still need to unpack the following archives:
  1809.     echo "        " ${MISSING}
  1810. fi
  1811. ##  End of shell archive.
  1812. exit 0
  1813. -- 
  1814. Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
  1815.     amiga@cs.odu.edu    
  1816. or    amiga@xanth.cs.odu.edu    ( obsolescent mailers may need this address )
  1817. or    ...!uunet!xanth!amiga    ( very obsolescent mailers need this address )
  1818.  
  1819. Comments, questions, and suggestions should be addressed to ``amiga-request''
  1820. (please only use ``amiga'' for actual submissions) at the above addresses.
  1821.